package top.kaoshanji.ch02;

import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.*;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.zip.CRC32;

/**
 * 代码清单 ch02-05：内存映射文件的性能(2.5.1节)
 * 执行之前需要先看看属性 FILE_PATH 指向的文件在本机是否存在
 * author kaoshanji
 * ^_^
 * create time 2024/12/6 18:06
 */
public class MemoryMapTest {

    private static final Logger logger = LogManager.getLogger(MemoryMapTest.class);

    // 文件路径
    static final String FILE_PATH = "D:\\program\\Java\\jdk-21\\lib\\src.zip";

    public static void main(String[] args) throws IOException {
        logger.info("...代码清单 ch02-05：内存映射文件的性能(2.5.1节)...");

        System.out.println("Input Stream:");
        long start = System.currentTimeMillis();
        Path filename = Paths.get(FILE_PATH);
        long crcValue = checksumInputStream(filename);
        long end = System.currentTimeMillis();
        System.out.println(Long.toHexString(crcValue));
        System.out.println((end - start) + " milliseconds");
        System.out.println();

        System.out.println("Buffered Input Stream:");
        start = System.currentTimeMillis();
        crcValue = checksumBufferedInputStream(filename);
        end = System.currentTimeMillis();
        System.out.println(Long.toHexString(crcValue));
        System.out.println((end - start) + " milliseconds");
        System.out.println();

        System.out.println("Random Access File:");
        start = System.currentTimeMillis();
        crcValue = checksumRandomAccessFile(filename);
        end = System.currentTimeMillis();
        System.out.println(Long.toHexString(crcValue));
        System.out.println((end - start) + " milliseconds");
        System.out.println();

        System.out.println("Mapped File:");
        start = System.currentTimeMillis();
        crcValue = checksumMappedFile(filename);
        end = System.currentTimeMillis();
        System.out.println(Long.toHexString(crcValue));
        System.out.println((end - start) + " milliseconds");

    }

    // 普通流读取
    public static long checksumInputStream(Path fileName) throws IOException {

        try (InputStream in = Files.newInputStream(fileName)) {
            var crc = new CRC32();

            int c;
            while ((c = in.read()) != -1) {
                crc.update(c);
            }

            return crc.getValue();
        }

    }

    // 缓存流读取
    public static long checksumBufferedInputStream(Path fileName) throws IOException {

        try (var in = new BufferedInputStream(Files.newInputStream(fileName))) {
            var crc = new CRC32();

            int c;
            while ((c = in.read()) != -1) {
                crc.update(c);
            }

            return crc.getValue();
        }

    }

    // 随机流读取
    public static long checksumRandomAccessFile(Path fileName) throws IOException {

        try (var file = new RandomAccessFile(fileName.toFile(), "r")){
            long length = file.length();
            var crc = new CRC32();

            for (long p = 0; p < length; p++) {
                file.seek(p);
                int c = file.readByte();
                crc.update(c);
            }

            return crc.getValue();
        }

    }

    // 内存映射读取
    public static long checksumMappedFile(Path fileName) throws IOException {

        try (FileChannel channel = FileChannel.open(fileName)) { // 第一步：使用 open 打开通道
            var crc = new CRC32();
            int length = (int) channel.size();

            // 第二步：调用 map 方法获得MappedByteBuffer
            MappedByteBuffer buffer = channel.map(FileChannel.MapMode.READ_ONLY, 0, length);

            // 第三步：操作 MappedByteBuffer
            for (int p = 0; p < length; p++) {
                int c = buffer.get(p);
                crc.update(c);
            }

            return crc.getValue();
        }

    }


}
